<!--
 * @Author: Dorange.Wang
 * @Date: 2021-04-14 17:19:29
 * @LastEditors: your name
 * @LastEditTime: 2021-11-18 15:20:20
 * @Description: file content
-->
<route>
{
  "meta":{
    "title":"WEBSQL",
    "showMenu":true,
    "serialNum": 50,
    "localism": "sys.websql"
  }
}
</route>
<template>
  <div class="websql">
    <draggable-sider @toggle="onToggle" @mouseMove="onToggle">
      <div
        class="websql__nav"
        :class="asideOpen ? '' : 'websql__nav--close'"
        slot="content"
      >
        <div class="websql__nav--header">
          <div v-show="asideOpen" class="websql__title">
            {{ $t("sys.model") }}
          </div>
          <!-- <div class="websql__aside" @click="asideOpen = !asideOpen">
            <IconPark
              v-show="asideOpen"
              size="24"
              type="menu-unfold-one"
              fill="#333"
            />
            <IconPark
              v-show="!asideOpen"
              size="24"
              type="menu-fold-one"
              fill="#333"
            />
          </div> -->
        </div>
        <div v-show="asideOpen" class="websql__nav--main mt10 pr10">
          <div class="websql__search">
            <el-input
              v-model="searchKey"
              :placeholder="$t('sys.search_by_code_or_name')"
              clearable
              :maxlength="64"
              prefix-icon="el-icon-search"
            />
          </div>
          <div class="websql__nav--tree mt10">
            <el-tree
              ref="tree"
              class="custom-tree"
              default-expand-all
              :data="modelTree"
              :props="{
                label: 'name',
                children: 'modelResults',
              }"
              :filter-node-method="filterNodeMethod"
            >
              <span class="custom-tree__node" slot-scope="{ data }">
                <span
                  class="custom-tree__span"
                  :title="[data.code, data.name] | codeName"
                  >{{ data.name }}</span
                >
                <el-dropdown
                  v-if="data.code"
                  placement="bottom"
                  @command="handleModelCommand($event, data)"
                >
                  <i class="el-icon-more" />
                  <el-dropdown-menu slot="dropdown">
                    <el-dropdown-item command="COPY">{{
                      $t("sys.copy_table_name")
                    }}</el-dropdown-item>
                    <el-dropdown-item
                      v-if="data._MODEL_TYPE_ !== 'system'"
                      command="FIELDS"
                      >{{ $t("sys.model_field") }}</el-dropdown-item
                    >
                    <el-dropdown-item command="SELECT">SELECT</el-dropdown-item>
                    <el-dropdown-item v-if="!isApp" command="TRUNCATE"
                      >TRUNCATE</el-dropdown-item
                    >
                  </el-dropdown-menu>
                </el-dropdown>
              </span>
            </el-tree>
          </div>
        </div>
      </div>
    </draggable-sider>

    <div class="websql__content">
      <div class="websql__content--tools pl10 pr10">
        <div>
          <el-button
            size="mini"
            type="primary"
            icon="el-icon-video-play"
            @click="handleRun"
            >{{ $t("sys.run") }}</el-button
          >
          <el-button
            size="mini"
            type="primary"
            icon="el-icon-upload"
            @click="handleSave"
            >{{ $t("sys.save_to_history") }}</el-button
          >
          <el-button
            size="mini"
            type="primary"
            icon="el-icon-s-open"
            v-if="!isApp"
            @click="handleClear"
            >{{ $t("sys.data_clear") }}</el-button
          >
        </div>
        <div class="websql__content--tools-right">
          <div @click="handleFormat">
            <IconPark size="18" type="optimize" fill="#333" />
          </div>
          <div @click="handleHistory">
            <IconPark size="18" type="history" fill="#333" />
          </div>
          <div @click="handleExecute">
            <IconPark size="18" type="history-query" fill="#333" />
          </div>
          <!-- <div @click="handleFormat">
            <IconPark size="18" type="help" fill="#333" />
          </div>
          <div @click="handleFormat">
            <IconPark size="18" type="full-screen" fill="#333" />
          </div> -->
        </div>
      </div>
      <div class="websql__content--run">
        <draggable-vertical
          :siblingMinHeight="siblingMinHeight"
          ref="draggableVertical"
          @getHeight="calcResultheight"
        >
          <div class="websql__content--sql pt10" slot="content">
            <div id="monaco-websql"></div>
          </div>
        </draggable-vertical>
        <div class="websql__content--result pl10">
          <Result ref="Result" />
        </div>
      </div>
    </div>

    <SaveForm ref="SaveForm" />
    <HistoryList ref="HistoryList" />
    <ExecuteList ref="ExecuteList" />
    <DataCleaning ref="DataCleaning" />
    <FieldList ref="FieldList" />
  </div>
</template>

<script>
import { getHmmodelfolderListTree } from "@/apis/paas/HmModelFolderController.js";
import { postHmwebsqlExecute } from "@/apis/paas/HmWebSqlController.js";
import * as monaco from "monaco-editor/esm/vs/editor/editor.api.js";
import { IconPark } from "@icon-park/vue/es/all";
import { encode, decode } from "js-base64";
import { copy } from "@/utils/util";
import { format } from "sql-formatter";
import SaveForm from "./SaveForm";
import HistoryList from "./HistoryList";
import ExecuteList from "./ExecuteList";
import DataCleaning from "./DataCleaning";
import FieldList from "./FieldList";
import Result from "./Result";
import DraggableVertical from "@/components/DraggableVertical/DraggableVertical";
import DraggableSider from "@/components/DraggableSider/DraggableSider";
import ResizableGrid from "@/components/ResizableGrid";
import { Debounce } from "@/utils/decorator.js";
import i18n from "@/i18n";
import { mapActions } from "vuex";
const SYSTEM_MODEL_TREE = [
  {
    name: i18n.t("sys.system_model"),
    modelResults: [
      {
        code: "act_hi_procinst",
        name: i18n.t("sys.process_instance_history"),
        _MODEL_TYPE_: "system",
      },
      {
        code: "act_hi_taskinst",
        name: i18n.t("sys.task_history"),
        _MODEL_TYPE_: "system",
      },
      {
        code: "act_hi_varinst",
        name: i18n.t("sys.variable_instance_history"),
        _MODEL_TYPE_: "system",
      },
      {
        code: "act_ru_task",
        name: i18n.t("sys.tasks_in_progress"),
        _MODEL_TYPE_: "system",
      },
    ],
  },
];

export default {
  name: "WebSql",

  components: {
    IconPark,
    SaveForm,
    HistoryList,
    ExecuteList,
    DataCleaning,
    FieldList,
    Result,
    DraggableVertical,
    DraggableSider,
    ResizableGrid,
  },

  data() {
    return {
      searchKey: "",
      modelTree: [],
      sqlEditorIns: null,
      sqlContent: "\n\n\n\n",
      loading: false,
      asideOpen: true,
      hasRange: false,
      siblingMinHeight: 0,
    };
  },

  watch: {
    searchKey(val) {
      this.$refs.tree.filter(val);
    },

    asideOpen() {
      setTimeout(() => {
        this.$nextTick(() => {
          this.sqlEditorIns.layout();
        });
      }, 300);
    },
  },
  computed: {
    isApp() {
      console.log(process.env.VUE_APP_ROOT_URL, "process.env.VUE_APP_ROOT_URL");
      return process.env.VUE_APP_ROOT_URL === "./";
    },
  },
  created() {
    this.setRouteAlive(this.$route.fullPath);
    this.loadModelTree();
  },

  mounted() {
    this.initSqlEditor();
    this.changeSize();
    window.addEventListener("resize", this.changeSize);
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.changeSize);
  },
  methods: {
    ...mapActions(["setRouteAlive"]),
    async loadModelTree() {
      const res = await getHmmodelfolderListTree({ modelTypes: "ENTITY" });
      this.modelTree = SYSTEM_MODEL_TREE.concat(res);
    },

    filterNodeMethod(value, data) {
      if (!value) return true;
      return (
        data.name.indexOf(value) !== -1 ||
        (data.code && data.code.indexOf(value) !== -1)
      );
    },

    initSqlEditor() {
      this.sqlEditorIns = monaco.editor.create(
        document.getElementById("monaco-websql"),
        {
          value: this.sqlContent,
          language: "sql",
          minimap: {
            enabled: false,
          },
        }
      );
    },

    async handleRun() {
      let content = "";
      const selection = this.sqlEditorIns
        .getModel()
        .getValueInRange(this.sqlEditorIns.getSelection());
      if (selection && selection.trim()) {
        content = selection;
      } else {
        content = this.sqlEditorIns.getValue() + "";
      }
      const sqls = content
        .replace(
          /;\s*(select|insert|update|delete|drop|alter|create|truncate)/gi,
          " _[SQL_START]_ " + "$1"
        )
        .split(" _[SQL_START]_ ")
        .filter((sql) => sql && sql.trim())
        .map((sql) => {
          let sqlTrim = sql.trim();
          if (sqlTrim.endsWith(";")) {
            sqlTrim = sqlTrim.substr(0, sqlTrim.length - 1);
          }
          return encode(sqlTrim);
        });
      const res = await postHmwebsqlExecute({
        sqls,
      });
      this.siblingMinHeight = res.length ? 150 : 0;
      this.$refs.Result.setResult(res);
      this.$nextTick(() => {
        this.$refs.draggableVertical &&
          this.$refs.draggableVertical.calcHeight();
        this.$refs.Result && this.$refs.Result.initTableHeight();
      });
    },

    async handleSave() {
      const content = this.sqlEditorIns.getValue() + "";
      if (!content.trim()) return;
      this.$refs.SaveForm.open({
        sqlContent: encode(content),
      });
    },

    handleHistory() {
      this.$refs.HistoryList.open({
        onActivate: (value) => {
          console.log(decode(value), "value");
          this.sqlEditorIns.setValue(decode(value));
          this.$refs.HistoryList.close();
        },
      });
    },
    // 执行历史
    handleExecute() {
      this.$refs.ExecuteList.open();
    },
    // 数据清理
    handleClear() {
      this.$refs.DataCleaning.open();
    },
    handleFormat() {
      const content = this.sqlEditorIns.getValue() + "";
      if (!content.trim()) return;
      this.sqlEditorIns.setValue(
        format(content, {
          linesBetweenQueries: 2,
        })
      );
    },

    handleModelCommand(command, data) {
      const prefix = data._MODEL_TYPE_ === "system" ? "" : "hm_model_";
      if (command === "COPY") {
        copy(`${prefix}${data.code}`);
      } else if (command === "SELECT") {
        const content = this.sqlEditorIns.getValue();
        this.sqlEditorIns.setValue(
          `select * from ${prefix}${data.code};\n\n` + content
        );
      } else if (command === "TRUNCATE") {
        const content = this.sqlEditorIns.getValue();
        this.sqlEditorIns.setValue(
          `truncate table ${prefix}${data.code};\n\n` + content
        );
      } else if (command === "FIELDS") {
        this.$refs.FieldList.open({
          modelId: data.id,
        });
      }
    },
    @Debounce(100)
    changeSize() {
      // 计算出table高度
      this.$refs.Result && this.$refs.Result.initTableHeight();
      this.$refs.draggableVertical && this.$refs.draggableVertical.calcHeight();
    },
    calcResultheight() {
      this.$refs.Result && this.$refs.Result.initTableHeight();
      this.onToggle();
    },
    @Debounce(100)
    onToggle() {
      setTimeout(() => {
        this.$nextTick(() => {
          this.sqlEditorIns.layout();
        });
      }, 200);
    },
  },
};
</script>

<style lang="scss" scoped>
.websql {
  display: flex;
  height: 100%;
  &__nav {
    flex: none;
    transition: width 0.3s;
    height: 100%;
    &--close {
      width: 36px;
    }

    &--header {
      height: 36px;
      font-size: 16px;
      font-weight: bold;
      line-height: 32px;
      border-bottom: 1px solid #eee;
      display: flex;
      align-items: center;
      justify-content: flex-end;
      padding-right: 10px;
      position: relative;

      & > div {
        display: flex;
        align-items: center;
      }
    }

    &--main {
      height: calc(100% - 47px);
    }

    &--tree {
      height: calc(100% - 42px);
      overflow-y: auto;
    }
  }

  &__title {
    position: absolute;
    left: 0;
    display: flex;
    align-items: center;
    height: 100%;
    top: 0;
  }

  &__aside {
    cursor: pointer;
  }

  &__content {
    flex: 1;
    min-width: 0;

    &--tools {
      height: 36px;
      border-bottom: 1px solid #eee;
      display: flex;
      align-items: center;
      justify-content: space-between;

      &-right {
        display: flex;
        align-items: center;
        justify-content: space-between;

        & > div {
          margin-left: 20px;
          cursor: pointer;
        }
      }
    }

    &--run {
      height: calc(100% - 37px);
      display: flex;
      flex-direction: column;
    }

    &--sql {
      height: 100%;
      box-sizing: border-box;
      border-bottom: 1px solid #eee;
      overflow: hidden;

      #monaco-websql {
        height: 100%;
      }
    }

    &--result {
      flex: 1;
      overflow: hidden;
      box-sizing: border-box;
    }
  }
}
</style>
